package org.jeecg.modules.paycenter.channel.zzbank.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.PayConstants;
import org.jeecg.modules.paycenter.channel.zzbank.dto.CorSinglePayDto;
import org.jeecg.modules.paycenter.channel.zzbank.dto.CreateSubAccountDto;
import org.jeecg.modules.paycenter.channel.zzbank.entity.HyZzbankAccount;
import org.jeecg.modules.paycenter.channel.zzbank.mapper.HyZzbankAccountMapper;
import org.jeecg.modules.paycenter.channel.zzbank.service.IHyZhengzhouBankService;
import org.jeecg.modules.paycenter.channel.zzbank.service.IHyZzbankAccountService;
import org.jeecg.modules.paycenter.channel.zzbank.util.SnowFlakeUtil;
import org.jeecg.modules.paycenter.channel.zzbank.vo.AllocateVo;
import org.jeecg.modules.paycenter.channel.zzbank.vo.WithdrawalVo;
import org.jeecg.modules.paycenter.enums.PayChannelEnum;
import org.jeecg.modules.paycenter.enums.UTypeEnum;
import org.jeecg.modules.third.digitalseal.utils.PdfToImageUtil;
import org.jeecg.modules.wlhy.bill.entity.*;
import org.jeecg.modules.wlhy.bill.service.*;
import org.jeecg.modules.wlhy.captain.entity.HyCaptain;
import org.jeecg.modules.wlhy.captain.service.IHyCaptainService;
import org.jeecg.modules.wlhy.hybank.entity.HyBank;
import org.jeecg.modules.wlhy.hybank.service.IHyBankService;
import org.jeecg.modules.wlhy.hydriverbank.entity.HyDriverBank;
import org.jeecg.modules.wlhy.hydriverbank.service.IHyDriverBankService;
import org.jeecg.modules.wlhy.utils.R;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class HyZzbankAccountServiceImpl extends ServiceImpl<HyZzbankAccountMapper, HyZzbankAccount> implements IHyZzbankAccountService {

    @Value(value="${zzBank.accountName:}")
    private String accountName;

    @Value(value="${zzBank.accountNo:}")
    private String accountNo;

    @Value(value="${zzBank.receiptUrl:}")
    private String receiptUrl;
    /**
     * PNG保存的目录
     */
    @Value(value="${params.path.upload:}")
    private String receiptDownLoadUrl;

    /**
     * PDF保存路径
     */

    @Value(value="${zzBank.pdfSavePath:}")
    private String pdfSavePath;


    @Resource private IHyZhengzhouBankService zhengzhouBankService;

    @Resource private IHyShippingNoteBillService shippingNoteBillService;

    @Resource private IHyDriverBillService driverBillService;
    @Resource private IHyCaptainBillService hyCaptainBillService;
    @Resource
    private IHyCarrierBillService carrierBillService;

    @Resource
    private IHyCustomerBillService customerBillService;

    @Resource
    private IHyDriverBankService driverBankService;
    @Resource
    private IHyBankService hyBankService;
    @Resource
    private IHyCaptainService hyCaptainService;

    /**
     * 创建郑州银行清分账户
     * @param createSubAccountDto
     * @return
     */
    @Override
    public HyZzbankAccount createSubAccount(CreateSubAccountDto createSubAccountDto) {
        HyZzbankAccount hyZzbankAccount = new HyZzbankAccount();
        hyZzbankAccount.setUid(createSubAccountDto.getUid());
        hyZzbankAccount.setUtype(createSubAccountDto.getUtype());
        hyZzbankAccount.setMainAccount(accountNo);
        hyZzbankAccount.setMainAccountName(accountName);

        Document document = zhengzhouBankService.createNoerrorBankAccount(createSubAccountDto.getAccName());
        if (ObjUtil.isNotEmpty(document)) {
            String processState = document.getElementsByTagName("ProcessState").item(0).getFirstChild().getNodeValue();
            if ("OK".equals(processState)) {
                String acName = document.getElementsByTagName("AcName").item(0).getFirstChild().getNodeValue();
                String acNo = document.getElementsByTagName("AcNo").item(0).getFirstChild().getNodeValue();
                hyZzbankAccount.setSubAccountName(acName);
                hyZzbankAccount.setSubAccount(acNo);
                hyZzbankAccount.setState("1");
                this.save(hyZzbankAccount);
                return hyZzbankAccount;
            } else {
                throw new RuntimeException("郑州银行开户失败");
            }
        }
        return null;
    }

    /**
     * 根据清分账户账号查询
     *
     * @param subAccNo
     * @return
     */
    @Override
    public String subAccountInfoByAccNo(String subAccNo) {
        log.info("查询郑州银行账户信息"+subAccNo);
        Document document = zhengzhouBankService.querySubAccInfo(subAccNo);
        log.info("查询郑州银行账户信息返回"+document.toString());
        if (ObjUtil.isNotEmpty(document)) {
            String totalRecord = document.getElementsByTagName("TotalRecord").item(0).getFirstChild().getNodeValue();
            if (totalRecord != null && Integer.parseInt(totalRecord) > 0) {
                NodeList s = document.getElementsByTagName("Map");
                if (s != null) {
                    Element node = (Element)s.item(0);
                    return node.getElementsByTagName("AcBalance").item(0).getFirstChild().getNodeValue();
                }
            }
        }
        return "0";
    }


    @Override
    public Map<String, String> transfer(WithdrawalVo transferVo) throws Exception {
        Document document = zhengzhouBankService.withdrawal(transferVo);
        Map<String, String> resultMap = new HashMap<>();
        String processState = document.getElementsByTagName("ProcessState").item(0).getFirstChild().getNodeValue();
        String transJnl = document.getElementsByTagName("TransJnl").item(0).getFirstChild().getNodeValue();

        resultMap.put("processState", processState);
        resultMap.put("transJnl", transJnl);
        return resultMap;
    }

    /**
     * @param erpJnlNo
     * @return
     */
    @Override
    public Map<String, String>  queryTransferResult(String erpJnlNo, String transJnl,String subAccNo,String transType, String startDate, String endDate) {
        Document document = zhengzhouBankService.queryPaymentResult(erpJnlNo,transJnl, subAccNo, transType, startDate, endDate);
        Map<String, String> resultMap = new HashMap<>();
        if (ObjUtil.isNotEmpty(document)) {
            String totalRecord = document.getElementsByTagName("TotalRecord").item(0).getFirstChild().getNodeValue();
            if (totalRecord != null && Integer.parseInt(totalRecord) > 0) {
                NodeList s = document.getElementsByTagName("Map");
                if (s != null) {
                    Element node = (Element)s.item(0);
                    resultMap.put("DealJnl", node.getElementsByTagName("DealJnl").item(0).getFirstChild().getNodeValue());
                    resultMap.put("TransStatus", node.getElementsByTagName("TransStatus").item(0).getFirstChild().getNodeValue());
                    return resultMap;
                }
            }
        }
        return null;
    }

    @Override
    public Map<String, String>  allocateTransfer(AllocateVo allocateVo) throws Exception {
        Document document = zhengzhouBankService.allocateTransfer(allocateVo);
        Map<String, String> resultMap = new HashMap<>();
        if (ObjUtil.isNotEmpty(document)) {
            String processState = document.getElementsByTagName("ProcessState").item(0).getFirstChild().getNodeValue();
            String transJnl = document.getElementsByTagName("TransJnl").item(0).getFirstChild().getNodeValue();
            resultMap.put("processState", processState);
            resultMap.put("transJnl", transJnl);
            return resultMap;
        }
        return null;
    }


    /**
     * @param driverBill
     * @return
     */
    @Override
    public R downloadReceipt4Driver(HyDriverBill driverBill) throws Exception {
        //根据流水号查询交易结果，交易结果回返回成交流水号
        String startDate = DateUtil.format(DateUtil.offsetDay(driverBill.getCreateTime(), -1), "yyyy-MM-dd");
        String endDate = DateUtil.format(DateUtil.offsetDay(driverBill.getCreateTime(), 1), "yyyy-MM-dd");
        log.info("开始查询交易数据---"+driverBill.getBillNum());
        Map<String, String> transResultMap = queryTransferResult(driverBill.getBillNum(), driverBill.getFrontFlowNo(),driverBill.getDbaccno(), "3", startDate, endDate);
        //根据交易流水号和成交流水号去查询回单文件名
        if (ObjUtil.isNotEmpty(transResultMap)) {
            String  dealJnl = transResultMap.get("DealJnl");
            log.info("开始查询回单文件名---erpJNL,{}----dealJnl：{}" ,driverBill.getBillNum(),dealJnl);
            //根据回单文件名下载回单
            Document fileNameDocument = zhengzhouBankService.queryReceipt(driverBill.getFrontFlowNo(), dealJnl);
            if (ObjUtil.isNotEmpty(fileNameDocument)) {
                String fileName = fileNameDocument.getElementsByTagName("FileName").item(0).getFirstChild().getNodeValue();
                zhengzhouBankService.downReceipt(fileName, SnowFlakeUtil.nextId().toString());
                //URL可以访问的文件路径
                String dateFolder = DateUtil.format(new Date(), "yyyy-MM-dd");
                String fileUrlPath = receiptUrl+"/"+dateFolder+"/"+fileName;
                //把这个URL地址的图片下载到本地的目录中保存下来
                HttpUtil.downloadFile(fileUrlPath, pdfSavePath+fileName);
                //PDF转化为PNG
                //文件名去除后缀
                String filenameNoSubfix = fileName.substring(0, fileName.lastIndexOf("."));
                String folderName = "/paybill/" + DateUtil.format(new Date(), "YYYYMM");
                String pngFileName = PdfToImageUtil.bankHdPdf2Jpg2(pdfSavePath, filenameNoSubfix, receiptDownLoadUrl+folderName+"/");

                shippingNoteBillService.lambdaUpdate()
                        .set(HyShippingNoteBill::getBankHd, "zhengzhoubank/"+fileName)
                        .set(HyShippingNoteBill::getBankHdImg, folderName +"/"+pngFileName)
                        .eq(HyShippingNoteBill::getShippingId, driverBill.getShippingId())
                        .update();

                driverBillService.lambdaUpdate()
                        .eq(HyDriverBill::getId, driverBill.getId())
                        .set(HyDriverBill::getBankReceipt, "zhengzhoubank/"+fileName)
                        .update();
            }

        }
        return R.ok();
    }

    /**
     * @param fileName
     * @return
     */
    @Override
    public String downloadReceipt4DriverByFileName(String fileName) throws Exception {
        return  zhengzhouBankService.downReceipt(fileName, SnowFlakeUtil.nextId().toString());
    }

    /**
     * @param singlePayDto
     * @param outAccountInfo
     * @return
     */
    @Override
    public R transfer4All(CorSinglePayDto singlePayDto, HyZzbankAccount outAccountInfo) throws Exception {
        WithdrawalVo transferVo = new WithdrawalVo();

        if (UTypeEnum.DRIVER.uType.equalsIgnoreCase(outAccountInfo.getUtype())) {
            transferVo.setRemark("司机提现");
            //获取司机银行卡
            HyDriverBank driverBank = driverBankService.lambdaQuery()
                    .eq(HyDriverBank::getDriverId, outAccountInfo.getUid())
                    .eq(HyDriverBank::getDelFlag,"0")
                    .eq(HyDriverBank::getBankNum, singlePayDto.getInAcctNo())
                    .one();
            HyBank bankInfo = hyBankService.getByBankType(driverBank.getBankType());
            if (ObjUtil.isEmpty(driverBank)) {
                return R.failed("请设置司机的默认银行卡");
            }
            if (ObjUtil.isEmpty(bankInfo)) {
                return R.failed("司机默认银行卡行号不能为空");
            }
            if (ObjUtil.isEmpty(driverBank.getBankName())) {
                return R.failed("司机默认银行卡开户行名称不能为空");
            }
            transferVo.setBankCode(bankInfo.getBankHh());
            transferVo.setPayeeAcNo(driverBank.getBankNum());
            transferVo.setPayeeAcName(driverBank.getBankName());
            transferVo.setPayeeBankName(bankInfo.getBankName());
        } else if (UTypeEnum.CAPTAIN.uType.equalsIgnoreCase(outAccountInfo.getUtype())) {
            transferVo.setRemark("承运商提现");
            //获取司机银行卡
            HyCaptain hyCaptain = hyCaptainService.getById(outAccountInfo.getUid());
            HyBank bankInfo = hyBankService.getByBankType(hyCaptain.getBankType());
            if (ObjUtil.isEmpty(hyCaptain.getBankNum())) {
                return R.failed("请设置承运商银行卡");
            }
            if (ObjUtil.isEmpty(hyCaptain.getBankName())) {
                return R.failed("承运商银行卡开户行名称不能为空");
            }
            transferVo.setBankCode(hyCaptain.getCrBankNo());
            transferVo.setPayeeAcNo(hyCaptain.getBankNum());
            transferVo.setPayeeAcName(hyCaptain.getBankName());
            transferVo.setPayeeBankName(bankInfo.getBankName());
        }

        transferVo.setPayerAcNo(outAccountInfo.getSubAccount());
        transferVo.setPayerAcName(outAccountInfo.getSubAccountName());
        transferVo.setTransAmt(singlePayDto.getTranAmount());
        transferVo.setErpJnlNo(SnowFlakeUtil.nextId().toString());

        Map<String, String> transResultMap = transfer(transferVo);
        if (UTypeEnum.DRIVER.uType.equalsIgnoreCase(outAccountInfo.getUtype())) { //司机
            this.driverCashOut(transResultMap, outAccountInfo, singlePayDto, transferVo);
        } else if (UTypeEnum.CARRIER.uType.equalsIgnoreCase(outAccountInfo.getUtype())) { //车队长
            this.carrierCashOut(transResultMap, outAccountInfo, singlePayDto);
        } else if (UTypeEnum.CUSTOMER.uType.equalsIgnoreCase(outAccountInfo.getUtype())) {  //货主
            this.customerCashOut(transResultMap, outAccountInfo, singlePayDto);
        } else if (UTypeEnum.CAPTAIN.uType.equalsIgnoreCase(outAccountInfo.getUtype())) {
            this.captainCashOut(transResultMap, outAccountInfo, singlePayDto, transferVo);
        }
        return R.ok(transResultMap);
    }


    /**
     * 司机提现写入司机流水记录
     *
     * @param resp
     * @param outAccountInfo
     * @param inAccountInfo
     */
    private void driverCashOut(Map<String, String> resp, HyZzbankAccount outAccountInfo, CorSinglePayDto inAccountInfo, WithdrawalVo transferVo) {
        //保存司机提现流水单
        HyDriverBill driverBill = new HyDriverBill();
        driverBill.setBillNum(transferVo.getErpJnlNo());
        driverBill.setBillType("2");//提现
        driverBill.setFrontFlowNo(resp.get("transJnl"));
        driverBill.setDriverId(outAccountInfo.getUid());
        driverBill.setDbaccno(outAccountInfo.getSubAccount());
        driverBill.setDblogaccno("");
        driverBill.setDbaccname(outAccountInfo.getSubAccountName());
        driverBill.setCraccno(inAccountInfo.getInAcctNo());
        driverBill.setCrlogaccno("");
        driverBill.setCraccname(inAccountInfo.getInAcctName());
        driverBill.setAmt(new BigDecimal(inAccountInfo.getTranAmount())); //提现金额
        driverBill.setRespSource("0");
        driverBill.setRespCode(PayConstants.BANK_PAY_SOUR.PROCESSING);
        driverBill.setRespInfo("");
        driverBill.setPayChannel(PayChannelEnum.ZHENGZHOU.channelType);
        driverBill.setCreateTime(new Date());
        driverBillService.save(driverBill);
    }


    /**
     * 车队长提现，写入车队长的流水记录
     *
     * @param transResult
     * @param outAccountInfo
     * @param inAccountInfo
     */

    private void carrierCashOut(Map<String, String> transResult, HyZzbankAccount outAccountInfo, CorSinglePayDto inAccountInfo) {
        HyCarrierBill carrierBill = new HyCarrierBill();
        carrierBill.setBillNum(transResult.get(""));
        carrierBill.setBillType("2");//提现
        carrierBill.setCarrierId(outAccountInfo.getUid());
        carrierBill.setDbaccno(outAccountInfo.getSubAccount());
        carrierBill.setDbaccname(outAccountInfo.getSubAccountName());
        carrierBill.setCraccno(inAccountInfo.getInAcctNo());
        carrierBill.setCraccname(inAccountInfo.getInAcctName());
        carrierBill.setAmt(new BigDecimal(inAccountInfo.getTranAmount())); //提现金额
        carrierBill.setPayChannel(PayChannelEnum.ZHENGZHOU.channelType);
        carrierBill.setRespSource("0");
        carrierBill.setRespCode(transResult.get(""));
        carrierBillService.save(carrierBill);
    }

    /**
     * 承运商提现
     * @param transResult
     * @param outAccountInfo
     * @param inAccountInfo
     */
    private void captainCashOut(Map<String, String> transResult, HyZzbankAccount outAccountInfo, CorSinglePayDto inAccountInfo, WithdrawalVo transferVo) {
        HyCaptainBill hyCaptainBill = new HyCaptainBill();
        hyCaptainBill.setBillNum(transferVo.getErpJnlNo());
        hyCaptainBill.setBillType("2");//提现
        hyCaptainBill.setFrontFlowNo(transResult.get("transJnl"));
        hyCaptainBill.setCarrierId(outAccountInfo.getUid());
        hyCaptainBill.setDbaccno(outAccountInfo.getSubAccount());
        hyCaptainBill.setDbaccname(outAccountInfo.getSubAccountName());
        hyCaptainBill.setCraccno(inAccountInfo.getInAcctNo());
        hyCaptainBill.setCraccname(inAccountInfo.getInAcctName());
        hyCaptainBill.setAmt(new BigDecimal(inAccountInfo.getTranAmount())); //提现金额
        hyCaptainBill.setPayChannel(PayChannelEnum.ZHENGZHOU.channelType);
        hyCaptainBill.setRespSource("0");
        hyCaptainBill.setRespCode(transResult.get("processState"));
        hyCaptainBillService.save(hyCaptainBill);
    }

    /**
     * 货主提现写入流水
     *
     * @param resp
     * @param outAccountInfo
     * @param inAccountInfo
     */

    private void customerCashOut(Map<String, String> resp, HyZzbankAccount outAccountInfo, CorSinglePayDto inAccountInfo) {
        HyCustomerBill bill = new HyCustomerBill();
        bill.setBillNum(resp.get(""));
        bill.setBillType("3");//提现
        bill.setCustomerId(outAccountInfo.getUid());
        bill.setDbaccno(outAccountInfo.getSubAccount());
        bill.setDbaccname(outAccountInfo.getSubAccountName());
        bill.setCraccno(inAccountInfo.getInAcctNo());
        bill.setCraccname(inAccountInfo.getInAcctName());
        bill.setAmt(new BigDecimal(inAccountInfo.getTranAmount())); //提现金额
        bill.setPayChannel(PayChannelEnum.PINGAN.channelType);
        bill.setRespSource("0");
        bill.setRespCode(resp.get(""));
        bill.setRespInfo("");
        customerBillService.save(bill);
    }

}
